// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/AuraAbilitySystemComponent.h"

#include "AbilitySystem/Abilities/AuraGameplayAbility.h"
#include "Aura/AuraLogChannels.h"
#include "Game/AuraGameplayTags.h"


void UAuraAbilitySystemComponent::HandleEffectApplied(
	UAbilitySystemComponent* ASC,
	const FGameplayEffectSpec& EffectSpec,
	FActiveGameplayEffectHandle ActiveEffectHandle
) const
{
	FGameplayTagContainer TagContainer;
	EffectSpec.GetAllAssetTags(TagContainer); /** 获得此游戏效果实例的所有标签 */

	EffectAssetTagsDelegate.Broadcast(TagContainer);
}

void UAuraAbilitySystemComponent::SetAbilitySystemWorkInfo()
{
	/** 当游戏效果应用到自身委托绑定相关事件 */
	OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &UAuraAbilitySystemComponent::HandleEffectApplied);
}

void UAuraAbilitySystemComponent::AddCharacterAbilities(TArray<TSubclassOf<UGameplayAbility>>& StartUpAbilityClasses)
{
	for (const TSubclassOf<UGameplayAbility> AbilityClass : StartUpAbilityClasses)
	{
		FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
		if (const UAuraGameplayAbility* AuraGameplayAbility = Cast<UAuraGameplayAbility>(AbilitySpec.Ability))
		{
			// 为能力实例添加动态标签
			AbilitySpec.DynamicAbilityTags.AddTag(AuraGameplayAbility->StartupInputTag);
			// 授予能力不激活 
			GiveAbility(AbilitySpec);
		}

	}

	bStartupAbilitiesGiven = true;
	AbilityGivenDelegate.Broadcast(this); // 服务端执行,导致客户端没有数据,解决:在OnRep_ActivatedAbilities()中广播
}

void UAuraAbilitySystemComponent::AddCharacterPassiveAbilities(
	TArray<TSubclassOf<UGameplayAbility>>& StartUpPassiveAbilityClasses
)
{
	for (const TSubclassOf<UGameplayAbility> AbilityClass : StartUpPassiveAbilityClasses)
	{
		FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);

			// 被动技能和主动技能的区别在于，被动技能应用即激活
			// 授予能力激活一次 
			GiveAbilityAndActivateOnce(AbilitySpec);
	}
}

void UAuraAbilitySystemComponent::AbilityTaggedInputTriggered(const FGameplayTag& InputTag)
{
	if (!InputTag.IsValid())
	{
		return;
	}

	for (FGameplayAbilitySpec AbilitySpec : GetActivatableAbilities())
	{
		if (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
		{
			AbilitySpecInputPressed(AbilitySpec);
			if (!AbilitySpec.IsActive())
			{
				TryActivateAbility(AbilitySpec.Handle);
			}
		}
	}
}


void UAuraAbilitySystemComponent::AbilityTaggedInputReleased(const FGameplayTag& InputTag)
{
	if (!InputTag.IsValid())
	{
		return;
	}

	for (FGameplayAbilitySpec AbilitySpec : GetActivatableAbilities())
	{
		if (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
		{
			AbilitySpecInputReleased(AbilitySpec);
		}
	}
}

void UAuraAbilitySystemComponent::ForeachCharacterAbilities(const FForeachAbility& Delegate)
{
	//使用域锁将此作用域this的内容锁定（无法修改），在遍历结束时解锁，保证线程安全
	FScopedAbilityListLock ActiveScopedLock(*this);

	for (FGameplayAbilitySpec& AbilitySpec : GetActivatableAbilities())
	{
		// 携带技能的委托广播出去
		if (!Delegate.ExecuteIfBound(AbilitySpec))
		{
			// __FUNCTION__ 预处理宏，返回当前函数名
			UE_LOG(LogAura, Error, TEXT("在函数[%hs}运行委托失败"), __FUNCTION__);

		}
	}
}

FGameplayTag UAuraAbilitySystemComponent::GetAbilityTagFormSpec(FGameplayAbilitySpec& Spec)
{
	if (Spec.Ability)
	{
		for (const FGameplayTag& Tag : Spec.Ability.Get()->AbilityTags)
		{
			if (Tag.MatchesTag(FGameplayTag::RequestGameplayTag(FName("Abilities"))))
			{
				return Tag;
			}
		}
	}

	return FGameplayTag();
}

FGameplayTag UAuraAbilitySystemComponent::GetInputTagFormSpec(FGameplayAbilitySpec& Spec)
{
	if (Spec.Ability)
	{
		for (const FGameplayTag& Tag : Spec.DynamicAbilityTags)
		{
			if (Tag.MatchesTag(FGameplayTag::RequestGameplayTag(FName("InputTag"))))
			{
				return Tag;
			}
		}
	}

	return FGameplayTag();
}

void UAuraAbilitySystemComponent::OnRep_ActivateAbilities()
{
	Super::OnRep_ActivateAbilities();

	if (!bStartupAbilitiesGiven)
	{
		bStartupAbilitiesGiven = true;
		AbilityGivenDelegate.Broadcast(this);
	}
}
